package com.tuliyou.common.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.*;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 基于 com.auth0:java-jwt 的 JWT 工具类
 */
public class JwtUtil {

    // 1. 密钥（必须保密，长度建议 >= 32 字符，用于 HMAC256 签名）
    private static final String SECRET_KEY = "Tuliyou-is-a-handsome-person";

    // 2. 令牌过期时间（单位：毫秒，此处为 24 小时）
    private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000;

    // 3. 签发者（可选，标识令牌的发行方）
    private static final String ISSUER = "tuliyou-system";

    /**
     * 生成 JWT 令牌
     * @param userId 用户ID（自定义载荷）
     * @param username 用户名（自定义载荷）
     * @return 生成的令牌字符串
     */
    public static String createToken(Long userId, String username,String userType) {
        // 当前时间
        Date now = new Date();
        // 过期时间
        Date expiration = new Date(now.getTime() + EXPIRATION_TIME);

        // 构建自定义载荷（claims）
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("username", username);
        claims.put("userType", userType);

        // 生成令牌
        return "Bearer "+JWT.create()
                // 设置签发者
                .withIssuer(ISSUER)
                // 设置签发时间
                .withIssuedAt(now)
                // 设置过期时间
                .withExpiresAt(expiration)
                // 添加自定义载荷（也可通过 withClaim 逐个添加）
                .withPayload(claims)
                // 使用 HMAC256 算法签名（密钥必须与验证时一致）
                .sign(Algorithm.HMAC256(SECRET_KEY));
    }

    /**
     * 从令牌中解析出 DecodedJWT 对象（包含所有信息）
     * @param token 令牌字符串
     * @return DecodedJWT 对象（解析失败会抛出异常）
     * @throws JWTVerificationException 解析失败（签名错误、过期等）
     */
    public static DecodedJWT decodeToken(String token) throws JWTVerificationException {
        // 创建验证器（指定算法、签发者）
        return JWT.require(Algorithm.HMAC256(SECRET_KEY))
                .withIssuer(ISSUER) // 验证签发者是否匹配
                .build()
                .verify(token); // 验证并解析令牌
    }

    /**
     * 从令牌中获取用户ID
     * @param token 令牌
     * @return 用户ID
     * @throws JWTVerificationException 解析失败
     */
    public static Long getUserId(String token) throws JWTVerificationException {
        DecodedJWT jwt = decodeToken(token);
        return jwt.getClaim("userId").asLong();
    }

    /**
     * 从令牌中获取用户名
     * @param token 令牌
     * @return 用户名
     * @throws JWTVerificationException 解析失败
     */
    public static String getUsername(String token) throws JWTVerificationException {
        DecodedJWT jwt = decodeToken(token);
        return jwt.getClaim("username").asString();
    }

    /**
     * 从令牌中获取用户名
     * @param token 令牌
     * @return 用户名
     * @throws JWTVerificationException 解析失败
     */
    public static String getUserType(String token) throws JWTVerificationException {
        DecodedJWT jwt = decodeToken(token);
        return jwt.getClaim("userType").asString();
    }

    /**
     * 验证令牌是否有效（包含签名、过期时间、用户信息匹配）
     * @param token 令牌
     * @param expectedUserId 预期的用户ID
     * @param expectedUsername 预期的用户名
     * @return true：有效；false：无效
     */
    public static boolean validateToken(String token, Long expectedUserId, String expectedUsername, String expectedUserType) {
        try {
            DecodedJWT jwt = decodeToken(token);
            // 验证自定义载荷中的用户信息是否匹配
            Long actualUserId = jwt.getClaim("userId").asLong();
            String actualUsername = jwt.getClaim("username").asString();
            String actualUserType = jwt.getClaim("userType").asString();
            return actualUserId.equals(expectedUserId) && actualUsername.equals(expectedUsername) && actualUserType.equals(expectedUserType);
        } catch (JWTVerificationException e) {
            // 任何验证失败都返回 false（如签名错误、过期、签发者不匹配等）
            return false;
        }
    }

    /**
     * 检查令牌是否已过期
     * @param token 令牌
     * @return true：已过期；false：未过期
     */
    public static boolean isTokenExpired(String token) {
        try {
            DecodedJWT jwt = decodeToken(token);
            return jwt.getExpiresAt().before(new Date());
        } catch (TokenExpiredException e) {
            // 捕获到过期异常，直接返回 true
            return true;
        } catch (JWTVerificationException e) {
            // 其他异常（如签名错误），视为无效令牌（过期状态不确定，返回 true 或 false 需根据业务定）
            return true;
        }
    }
}
